package com.example.dishit.service.dishpoll;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;
import android.os.Process;

import com.example.dishit.controller.main.MainController;
import com.example.dishit.model.dbproxy.DBProxyFactory;
import com.example.dishit.model.dbproxy.IDBProxyCallback;
import com.example.dishit.model.dbproxy.data.Dish;
import com.example.dishit.model.dish.DishData;
import com.example.dishit.view.alert.AlertView;

public class DishPollingServiceFactory {
    private static final IDishPollingService service = new DishPollingService();
    
    private static Boolean isRunning = false;
    
    //private static long POLL_RATE_MILLIS = 10000; // every 10 seconds
    private static long POLL_RATE_MILLIS = 120000; // every 2 minutes
    //private static long POLL_RATE_MILLIS = 100000000000L; // i.e. never
    
    public static IDishPollingService instance() { return service; }
    
    private static class DishPollingService implements IDishPollingService {
        private final Executor pollingThread = Executors.newSingleThreadExecutor();
        
        public void start(final Context context) {
            synchronized(isRunning) {
                // If already running, then return.
                if(isRunning) return;
                
                isRunning = true;
            }
            
            // Start the polling service.
            pollingThread.execute(new DishPollingRunnbale(context));
        }
        
        public void stop() {
            synchronized(isRunning) {
                // If already stopped, then return.
                if(!isRunning) return;
                
                isRunning = false;
            }
        }
    }
    
    private static class DishPollingRunnbale implements Runnable {
        private final Handler handler;
        private long lastPollTimeMillis = System.currentTimeMillis();
        
        public DishPollingRunnbale(final Context context) {
            // Setup the HandlerThread (to draw the alert).
            final HandlerThread thread = new HandlerThread("ServiceStartArguments",
                                                           Process.THREAD_PRIORITY_BACKGROUND);
            thread.start();
            this.handler = new Handler(thread.getLooper()) {
                @Override
                public void handleMessage(Message msg) {
                    final Bundle bundle = msg.getData();
                    final List<DishData> dishDatas = (List<DishData>)bundle.getSerializable(DishData.DISH_DATA_KEY);
                    
                    // Automatically add the received dish to the main list.
                    MainController.instance().setReceivedDishes(dishDatas);
                }
            };
        }
        
        public void run() {
            final String myUserId = MainController.THIS_USER_ID;
            while(true) {
                // Sleep for 'x' seconds.
                try { Thread.sleep(POLL_RATE_MILLIS); } catch (InterruptedException e) { e.printStackTrace(); }
                
                // Cache-off the last polling time.
                final long prevPollTimeMillis = lastPollTimeMillis;
                // Update the last polling time.
                lastPollTimeMillis = System.currentTimeMillis();
                
                // Get any new Dishes from my Dishers.
                DBProxyFactory.instance().getLatestReceivedDishes(myUserId,
                                                                  prevPollTimeMillis,
                                                                  new IDBProxyCallback() {
                    public void onResultCallback(boolean wasSuccessful, String message) {}
                    public void onDishersCallback(List<String> myDishers) {}
                    public void onDishDataCallback(List<DishData> dishDatas) {
                        // If new Dishes found, handle it appropriately.
                        if(dishDatas != null) {
                            final Message msg = handler.obtainMessage();
                            final Bundle bundle = msg.getData();
                            bundle.putSerializable(DishData.DISH_DATA_KEY, (Serializable)dishDatas);
                            msg.setData(bundle);
                            handler.sendMessage(msg);
                        }
                    }
                });
                
                synchronized(isRunning) {
                    // If stop is requested, then break.
                    if(!isRunning) break;
                }
            }
        }
    }
}
